using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.DirectX.DirectInput;
using System.Drawing;
using SharpWars.Core.Helpers;
using System.Windows.Forms;

namespace SharpWars.Core.Input
{
	public sealed class Mouse
	{
		private Device device = null;

		private GameWindow gameWindow = null;

		private bool[] keysPressed = null;

		private bool[] keysTriggered = null;

		private bool isLost = false;

		private bool clamp = true;

		private bool hide = false;

		private PointF absPosition = PointF.Empty;
		private PointF relPosition = PointF.Empty;

		public Mouse()
		{
			this.keysPressed = new bool[ 8 ];
			this.keysTriggered = new bool[ 8 ];
		}

		internal void Initialize( GameWindow gameWindow )
		{
			this.gameWindow = gameWindow;

			this.device = new Device( SystemGuid.Mouse );
			this.device.SetDataFormat( DeviceDataFormat.Mouse );
			this.device.SetCooperativeLevel( gameWindow, CooperativeLevelFlags.Background |
											 CooperativeLevelFlags.NonExclusive );

			try
			{
				this.device.Acquire();
			}
			catch( InputLostException )
			{
				this.isLost = true;
			}
		}

		public void Update()
		{
			if( this.device == null )
			{
				return;
			}

			try
			{
				this.device.Acquire();
			}
			catch( InputLostException )
			{
				return;
			}

			MouseState currentState = this.device.CurrentMouseState;

			byte[] p = currentState.GetMouseButtons();
			List<int> pressed = new List<int>();
			for( int i = 0; i < p.Length; i++ )
			{
				if( p[ i ] != 0 )
				{
					pressed.Add( i );
				}
			}

			UpdateTriggeredKeys( pressed.ToArray() );
			UpdatePressedKeys( pressed.ToArray() );
			UpdatePosition( currentState );


		}

		private void UpdatePosition( MouseState currentState )
		{
			this.relPosition.X = currentState.X;
			this.relPosition.Y = currentState.Y;

			// Jesli exclusive
// 			this.absPosition.X += currentState.X;
// 			this.absPosition.Y += currentState.Y;

			// Wyrownanie do przestrzeni klienta
			Point Shift = Cursor.Position;
			Shift.X -= gameWindow.Location.X + Utils.Borders.X;
			Shift.Y -= gameWindow.Location.Y + Utils.Borders.Y;

			this.absPosition = Shift;		

			if( this.clamp )
			{
				absPosition.X = Utils.Clamp( 0.0f, 640.0f, absPosition.X );
				absPosition.Y = Utils.Clamp( 0.0f, 480.0f, absPosition.Y );

// 				if( this.absPosition.X < 0 )
// 				{
// 					this.absPosition.X = 0;
// 				}
// 				else if( this.absPosition.X > this.gameWindow.ClientSize.Width )
// 				{
// 					this.absPosition.X = this.gameWindow.ClientSize.Width;
// 				}
// 
// 				if( this.absPosition.Y < 0 )
// 				{
// 					this.absPosition.Y = 0;
// 				}
// 				else if( this.absPosition.Y > this.gameWindow.ClientSize.Height )
// 				{
// 					this.absPosition.Y = this.gameWindow.ClientSize.Height;
// 				}
			}

// 			string Info = string.Format( "Rel={0} Abs={1}", relPosition, absPosition );
// 			System.Diagnostics.Debug.WriteLine( Info );
		}

		private void UpdateTriggeredKeys( int[] pressed )
		{
			for( int i = 0; i < this.keysTriggered.Length; i++ )
			{
				this.keysTriggered[ i ] = false;
			}

			for( int i = 0; i < pressed.Length; i++ )
			{
				int key = pressed[ i ];

				if( !this.keysPressed[ key ] )
				{
					this.keysTriggered[ key ] = true;
				}
			}
		}

		private void UpdatePressedKeys( int[] pressed )
		{
			for( int i = 0; i < this.keysPressed.Length; i++ )
			{
				this.keysPressed[ i ] = false;
			}

			for( int i = 0; i < pressed.Length; i++ )
			{
				int key = pressed[ i ];
				this.keysPressed[ key ] = true;
			}
		}

		public bool IsButtonPressed( MouseButton button )
		{
			return this.keysPressed[ ( int )button ];
		}

		public bool IsButtonTriggered( MouseButton button )
		{
			return this.keysTriggered[ ( int )button ];
		}

		// 		public bool HideWindowsCursor
		// 		{
		// 			get
		// 			{
		// 				return this.hide;
		// 			}
		// 			set
		// 			{
		// 				this.hide = value;
		// 				if( value )
		// 				{
		// 					Cursor.Hide();
		// 				}
		// 				else
		// 				{
		// 					Cursor.Show();
		// 				}
		// 			}
		// 		}

		public bool Clamp
		{
			get
			{
				return this.clamp;
			}
			set
			{
				this.clamp = value;
			}
		}

		public PointF AbsolutePosition
		{
			get
			{
				return this.absPosition;
			}
		}

		public PointF RelativePosition
		{
			get
			{
				return this.relPosition;
			}
		}

		#region IDisposable Members

		public void Dispose()
		{
			if( this.device != null )
			{
				this.device.Unacquire();
				DisposeHelper.Dispose( this.device );
			}
		}

		#endregion

	}
}
